package uhaleks;

import uhaleks.shape.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;
import java.util.*;
import java.io.*;
import java.nio.charset.Charset;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.List;

class StaticTest {
    static int iTest = 25;
}

class Incrementable {
    static void increment() { StaticTest.iTest++; }
}

/**
 * Класс, содержащий два непроинициализированных поля
 * Создан для того, чтобы убедиться, что Java их инициализирует по умолчанию
 */
class NotInitField {
    int age;
    char name;
}

class DataOnly {
    int i;
    double d;
    boolean b;
    {
        i = 10;
        d = 154.988d;
        b = false;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int inputInt;
        double inputDouble;
        while (true) {
            System.out.print("Введите номер задания: ");
            switch (scanner.nextInt()) {
                case 1:
                    System.out.println("Hello, world!");
                    break;
                case 2:
                    NotInitField not_init = new NotInitField();
                    System.out.println("Возраст: " + not_init.age);
                    System.out.println("Имя: " + (char) 0x22 + not_init.name + (char) 0x22);
                    break;
                case 3:
                    System.out.println("Это пример демонстрирует работу со статическими элементами класса");
                    System.out.println("Начальное значение: " + StaticTest.iTest);
                    Incrementable.increment(); // обращение через указание класса
                    System.out.println("После инкремента (вызов метода через указание класса): " + StaticTest.iTest);
                    Incrementable inc = new Incrementable();
                    inc.increment(); // обращение через объект
                    System.out.println("После инкремента (вызов метода через объект): " + StaticTest.iTest);
                    break;
                case 4:
                    System.out.println("Следующие поля были инициализированы:");
                    DataOnly data_only = new DataOnly();
                    System.out.println("i = " + data_only.i + "\nd = " + data_only.d + "\nb = " + data_only.b);
                    break;
                case 5:
                    System.out.println("Автоупаковка и распаковка");
                    Integer iTest5 = 5; // автоупаковка
                    System.out.println("i = " + iTest5);
                    int countTest5 = 51;
                    iTest5 += countTest5 % 2; // автоупаковка
                    System.out.println("i = " + iTest5);
                    countTest5 = iTest5; // распаковка
                    System.out.println("count = " + countTest5);
                    break;
                case 6:
                    System.out.println("Демонстрация смысла статических полей");
                    StaticTest st1 = new StaticTest();
                    StaticTest st2 = new StaticTest();
                    st1.iTest = 50;
                    System.out.println("Статическое поле объекта1 имеет значение " + st1.iTest);
                    System.out.println("Статическое поле объекта2 (того же класса) имеет значение " + st2.iTest);
                    break;
                case 7:
                    System.out.println("Демонстрация работы класса Дробное число");
                    System.out.println("Введите два дробных числа (только положительные)");
                    System.out.print("Число 1. Целая часть: ");
                    long left1 = scanner.nextLong();
                    System.out.print("Число 1. Дробная часть: ");
                    short right1 = scanner.nextShort();
                    System.out.print("Число 2. Целая часть: ");
                    long left2 = scanner.nextLong();
                    System.out.print("Число 2. Дробная часть: ");
                    short right2 = scanner.nextShort();
                    Fractions f;
                    Fractions f1 = new Fractions(left1, right1);
                    Fractions f2 = new Fractions(left2, right2);
                    System.out.print("Сумма: ");
                    f = f1.sum(f2);
                    System.out.println(f.toString());
                    System.out.print("Разность: ");
                    f = f1.sub(f2);
                    System.out.println(f.toString());
                    break;
                case 8:
                    System.out.println("Равнобедренная трапеция");
                    System.out.print("Укажите количество создаваемых фигур: ");
                    int count_trap = scanner.nextInt();
                    ArrayList<IsoscelesTrapezoid> list = new ArrayList<IsoscelesTrapezoid>();
                    Random rand = new Random();
                    for (int j = 0; j < count_trap; j++) {
                        IsoscelesTrapezoid trap = new IsoscelesTrapezoid(rand.nextInt(2), rand.nextInt(2),
                                1 + rand.nextInt(2), 5 + rand.nextInt(2), 7 + rand.nextInt(2), 5 + rand.nextInt(2),
                                9 + rand.nextInt(2), rand.nextInt(2));
                        list.add(trap);
                        if (list.get(j).checkIsosceles()) {
                            System.out.println("Фигура является равнобедренной трапецией");
                            System.out.println("  Нижнее основание = " + trap.sideLength(Side.BOTTOM));
                            System.out.println("  Периметр = " + trap.perimeter());
                            System.out.println("  Площадь = " + trap.area());
                        } else
                            System.out.println("Фигура НЕ является равнобедренной трапецией");
                    }
                    break;
                case 9:
                    System.out.println("=== Расчет площади фигур ===");
                    System.out.println("1.Квадрат\n2.Окружность\n3.Прямоугольник\n4.Треугольник");
                    System.out.print("Выберите фигуру: ");
                    uhaleks.shape.Shape shape;
                    switch (scanner.nextInt()) {
                        case 1:
                            System.out.print("Укажите ширину: ");
                            shape = new uhaleks.shape.Square(scanner.nextDouble());
                            break;
                        case 2:
                            System.out.print("Укажите радиус: ");
                            shape = new uhaleks.shape.Circle(scanner.nextDouble());
                            break;
                        case 3:
                            System.out.print("Укажите ширину и высоту: ");
                            shape = new uhaleks.shape.Rectangle(scanner.nextDouble(), scanner.nextDouble());
                            break;
                        case 4:
                            System.out.print("Укажите длины трех сторон: ");
                            shape = new uhaleks.shape.Triangle(scanner.nextDouble(), scanner.nextDouble(), scanner.nextDouble());
                            break;
                        default:
                            shape = new uhaleks.shape.Square(scanner.nextDouble());
                            break;
                    }
                    System.out.println("Площадь = " + shape.area());
                    break;
                case 10:
                    System.out.println("=== Двунаправленный список ===");
                    uhaleks.LinkedList<String> linkedList = new uhaleks.LinkedList<String>();
                    // проверка всех методов класса LinkedList
                    linkedList.add("Великолепными коврами,");
                    linkedList.add("Прозрачный лес один чернеет,");
                    linkedList.add(1, "Блестя на солнце, снег лежит;");
                    linkedList.addLast("И ель сквозь иней зеленеет,");
                    linkedList.addFirst("Под голубыми небесами");
                    linkedList.add("И речка подо льдом блестит.");
                    linkedList.removeLast(); // !! удалим первую и последнию строку стиха
                    linkedList.removeFirst();
                    System.out.println(linkedList.getFirst());
                    for (int k = 1; k < linkedList.size() - 1; k++)
                        System.out.println(linkedList.get(k));
                    System.out.println(linkedList.getLast());
                    String searchList = "Блестя на солнце, снег лежит;";
                    System.out.print("Поиск строки: \"" + searchList + "\" ");
                    System.out.println("Число вхождений элемента в список = " + linkedList.count(searchList));
                    if (linkedList.empty())
                        System.out.println("Список пуст!");
                    else
                        System.out.println("Список не пустой");
                    System.out.println("Количество элементов в списке = " + linkedList.size());
                    System.out.println("\n=== Сортированный двунаправленный список ===");
                    uhaleks.SortedIntegerLinkedList sortIntList = new SortedIntegerLinkedList();
                    Random rand2 = new Random();
                    for (int k = 0; k < 5; k++)
                        sortIntList.add(rand2.nextInt(100));
                    for (int k = 0; k < sortIntList.size(); k++)
                        System.out.println(sortIntList.get(k));
                    break;
                case 11:
                    System.out.println("=== Про Красную Шапочку ===");
                    int n = 0, x = 0, y = 0;
                    try {
                        Scanner inData = new Scanner(new File("input.txt"));
                        n = inData.nextInt();
                        x = inData.nextInt();
                        y = inData.nextInt();
                        inData.close();
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    // пока ввод данных сделан через консоль
                    /*System.out.print("Укажите длину и ширину леса в квадратах (одно значение): ");
                    int n = scanner.nextInt();
                    System.out.print("Координаты серого волка x: ");
                    int x = scanner.nextInt();
                    System.out.print("y: ");
                    int y = scanner.nextInt();*/
                    WaysInPlane redRidingHood = new WaysInPlane();
                    System.out.println("Количество кратчайших путей до дома бабушки = " + redRidingHood.numberWays(n, n));
                    int numberWaysWolf = redRidingHood.numberWays(x, y) * redRidingHood.numberWays(n - x + 1, n - y + 1);
                    System.out.println("Количество кратчайших путей до дома бабушки через волка = " + numberWaysWolf);
                    break;
                case 12: {
                    System.out.println("Разбор тектового файла на слова");
                    System.out.println("Входной файл: text.txt");
                    Path inFile = Paths.get("text.txt");
                    Charset inCharset = Charset.forName("UTF-8");
                    String s = "";
                    try {
                        byte[] inBytes = Files.readAllBytes(inFile);
                        s = new String(inBytes, inCharset);
                    } catch (IOException e) {
                        System.err.format("IOException: %s%n", e);
                    }

                    s = s.toLowerCase();
                    s = s.replaceAll("[^a-zа-яё_0-9-\\s]", "");
                    s = s.replaceAll("\\s-\\s", " ");
                    s = s.trim();
//                    System.out.println(s);

                    Pattern p = Pattern.compile("\\s+");
                    String[] words = p.split(s);
                    int numWords = words.length;

//                    for (int i = 0; i < words.length; i++)
//                        System.out.println(words[i]);

                    ArrayList<Word> aW = new ArrayList<Word>();
                    if (words.length != 0)
                        aW.add(new Word(words[0], 1));
                    else
                        System.out.println("Список слов пуст!");
                    for (int i = 1; i < words.length; i++) {
                        for (int j = 0; j < aW.size(); j++) {
                            if (words[i].equals(aW.get(j).getWord())) {
                                aW.get(j).incFreq();
                                break;
                            }
                            if (j == aW.size() - 1) {
                                aW.add(new Word(words[i], 1));
                                break;
                            }
                        }
                    }

//                    for (int i = 0; i < aW.size(); i++)
//                        System.out.println(aW.get(i));

                    Collections.sort(aW, Collections.reverseOrder());

//                    for (int i = 0; i < aW.size(); i++)
//                        System.out.println(aW.get(i));

                    Path csvFile = Paths.get("words.csv");
                    Charset charset = Charset.forName("Windows-1251");
                    try {
                        String buf = "";
                        for (int i = 0; i < aW.size(); i++) {
                            double procFreq;
                            procFreq = Math.rint(100d * aW.get(i).getFreq() / numWords * 100) / 100d;
                            buf += aW.get(i).toString() + "; " + procFreq + "\r\n";
                        }
                        Files.write(csvFile, buf.getBytes(charset));
                        System.out.println("Разбор текста закончен\nНайдено слов " + numWords);
                        System.out.println("слов с учетом повторений " + aW.size());
                        System.out.println("Файл words.csv создан");
                    } catch (IOException e) {
                        System.err.format("IOException: %s%n", e);
                    }

                    break;
                }
                case 14: {
                    System.out.println("=== Палиндром ===");
                    System.out.println("Будет вычислена максимальная длина палиндрома, получаемая из строки ");
                    System.out.println("путем удаления некоторого числа (возможно нуля) произвольных букв");
                    System.out.println("1. Загрузить из файла input14.txt");
                    System.out.print("2. Ввести с консоли\n3. Сгенерировать случайно\nВыберите способ ввода строки: ");
                    String s = "";
                    switch (scanner.nextInt()) {
                        case 1:
                            Path inFile = Paths.get("input14.txt");
                            Charset inCharset = Charset.defaultCharset();
                            try {
                                byte[] inBytes = Files.readAllBytes(inFile);
                                s = new String(inBytes, inCharset);
                            } catch (IOException e) {
                                System.err.format("IOException: %s%n", e);
                            }
                            break;
                        case 2:
                            System.out.println("Введите строку (например, aabadba):");
                            s = scanner.next();
                            break;
                        case 3:
                            System.out.print("Укажите длину строки (не более 100 символов): ");
                            int length = scanner.nextInt();
                            System.out.print("Укажите правую границу диапазона символов [a; _] (например, f): ");
                            char rightLimit = scanner.next().charAt(0);
                            int range = rightLimit - 'a' + 1;
                            Random random = new Random();
                            for (int i = 0; i < length; i++)
                                s += (char)('a' + random.nextInt(range));
                            break;
                        default:
                            s = "a";
                            break;
                    }
                    if (s.length() != 0) {
                        System.out.println("Исходная строка: " + s);
                        Palindrome palindrome = new Palindrome(s);
                        System.out.println("Максимальная длина палиндрома = " + palindrome.maxLength());
                    }
                    break;
                }
                default:
                    System.out.println("Задание не найдено!");
                    break;
                case 0:
                    System.out.println("Завершение программы...");
                    return;
            }
            System.out.println("------------------------");
            System.out.println();
        }
    }
}
